#include <math.h>
#include <windows.h>
#include "CStats.h"
#include "CUtil.h"

	/* Hume            D  D  D  D  D  D  D  D  D */
int raceGrades[5][9]={{4, 4, 4, 4, 4, 4, 4, 4, 4},
	/* Elvaan          C  E  B  E  C  F  F  B  D */
					  {3, 5, 2, 5, 3, 6, 6, 2, 4},
	/* Taru            G  A  F  D  E  C  A  E  D */
					  {7, 1, 6, 4, 5, 3, 1, 5, 4},
	/* Mithra          D  D  E  A  E  B  D  E  F */
					  {4, 4, 5, 1, 5, 2, 4, 5, 6},
	/* Galka           A  G  C  D  A  E  E  D  F */
					  {1, 7, 3, 4, 1, 5, 5, 4, 6}};

int jobGrades[20][9]  = 
  /* WAR                  B  x  A  C  D  C  F  F  E */
						{{2, 0, 1, 3, 4, 3, 6, 6, 5},
  /* MNK                  A  x  C  B  A  F  G  D  E */
						 {1, 0, 3, 2, 1, 6, 7, 4, 5},
  /* WHM                  E  C  D  F  D  E  E  A  C */
						 {5, 3, 4, 6, 4, 5, 5, 1, 3},
  /* BLM                  F  B  F  C  F  C  A  E  D */
						 {6, 2, 6, 3, 6, 3, 1, 5, 4},
  /* RDM                  D  D  D  D  E  E  C  C  D */
						 {4, 4, 4, 4, 5, 5, 3, 3, 4},
  /* THF                  D  x  D  A  D  B  C  G  G */
						 {4, 0, 4, 1, 4, 2, 3, 7, 7},
  /* PLD                  C  F  B  E  A  G  G  C  C */
						 {3, 6, 2, 5, 1, 7, 7, 3, 3},
  /* DRK                  C  F  A  C  C  D  C  G  G */
						 {3, 6, 1, 3, 3, 4, 3, 7, 7},
  /* BST                  C  x  D  C  D  F  E  E  A */
						 {3, 0, 4, 3, 4, 6, 5, 5, 1},
  /* BRD                  D  x  D  D  D  F  D  D  B */
						 {4, 0, 4, 4, 4, 6, 4, 4, 2},
  /* RNG                  E  x  E  D  D  A  E  D  E */
						 {5, 0, 5, 4, 4, 1, 5, 4, 5},
  /* SAM                  B  x  C  C  C  D  E  E  D */
						 {2, 0, 3, 3, 3, 4, 5, 5, 4},
  /* NIN                  D  x  C  B  C  B  D  G  F */
						 {4, 0, 3, 2, 3, 2, 4, 7, 6},
  /* DRG                  C  x  B  D  C  D  F  E  C */
						 {3, 0, 2, 4, 3, 4, 6, 5, 3},
  /* SMN                  G  A  F  E  F  D  B  B  B */
						 {7, 1, 6, 5, 6, 4, 2, 2, 2},
  /* BLU                  D  D  E  E  E  E  E  E  E */
						 {4, 4, 5, 5, 5, 5, 5, 5, 5},
  /* COR                  D  x  E  C  E  C  C  E  E */
						 {4, 0, 5, 3, 5, 2, 3, 5, 5},
  /* PUP                  D  x  E  B  D  C  E  F  C */
						 {4, 0, 5, 2, 4, 3, 5, 6, 3},
  /* DNC                  D  x  D  C  E  B  F  F  B */
						 {4, 0, 4, 3, 5, 2, 6, 6, 2},
  /* SCH                  E  D  F  D  E  D  C  D  C */
						 {5, 4, 6, 4, 5, 4, 3, 4, 3}};

float hpScale[8][5] = {{ 0, 0, 0, 0},
					   {19, 9, 1, 3},
					   {17, 8, 1, 3},
					   {16, 7, 1, 3},
					   {14, 6, 0, 3},
					   {13, 5, 0, 2},
					   {11, 4, 0, 2},
					   {10, 3, 0, 2}};

float mpScale[8][4] = {{ 0, 0,   0},
					   {16, 6,   4},
					   {14, 5,   4},
					   {12, 4,   4},
					   {10, 3,   4},
					   { 8, 2,   3},
					   { 6, 1,   2},
					   { 4, 0.5, 1}};

double statScale[8][4] = {{ 0,    0,   0},
				  	     { 5, 0.50, 0.10},
					     { 4, 0.45, 0.20},
					     { 4, 0.40, 0.25},
					     { 3, 0.35, 0.35},
					     { 3, 0.30, 0.35},
					     { 2, 0.25, 0.40},
					     { 2, 0.20, 0.40}};


CStats::CStats() {
	memset(this,0,sizeof(CStats));
}

int CStats::getJobGrade(int x, int y) {

	return jobGrades[x-1][y];

}

int CStats::calcMaxHP( int raceIndex, int mjob, int mlvl, int sjob, int slvl ) 
{
  int baseValueColumn = 0;
  int scaleTo60Column = 1;
  int scaleOver60Column = 3;
  int scaleOver30Column = 2;
  int hpIndex = 0;
  int grade;
  
  int mainLevelOver10;
  int mainLevelOver30;
  int mainLevelOver60;
  int mainLevelUpTo60;
  int mainLevelOver50andUnder60;
  int subLevelOver10;
  int subLevelOver30;

  int raceHP;
  int jobHP;
  int sjobHP;
  int bonusHP = 0;

  /* First scale up to 60 */
  mainLevelUpTo60 = mlvl - 1;
  if (mainLevelUpTo60 > 59)
    mainLevelUpTo60 = 59;

  /* Different scale over level 60 */
  mainLevelOver60 = mlvl - 60;
  if (mainLevelOver60 < 0)
    mainLevelOver60 = 0;

  /* +1 per level over 30 (depends on HP rating) */
  mainLevelOver30 = mlvl - 30;
  if (mainLevelOver30 < 0)
    mainLevelOver30 = 0;
  if (mainLevelOver30 > 30)
    mainLevelOver30 = 30;

  /* ##################################### */
  /* Bonus HP levels */
  
  /* +2 per level over 10 (all) */
  mainLevelOver10 = mlvl - 10;
  if (mainLevelOver10 < 0)
    mainLevelOver10 = 0;

  /* +2 per level over 50 and under 60 */
  mainLevelOver50andUnder60 = mlvl - 50;
  if (mainLevelOver50andUnder60 < 0)
    mainLevelOver50andUnder60 = 0;
  if (mainLevelOver50andUnder60 > 10)
    mainLevelOver50andUnder60 = 10;
    
  /* ##################################### */
  /* Subjob bonus levels */
  
  /* +1 per level over 10 (/2) */
  subLevelOver10 = slvl - 10;
  if (subLevelOver10 < 0)
    subLevelOver10 = 0;
  if (subLevelOver10 > 20)
    subLevelOver10 = 20;

  /* +1 per level over 30 */
  subLevelOver30 = slvl - 30;
  if (subLevelOver30 < 0)
    subLevelOver30 = 0;

  
  /* --------------------------------------------------- */
  /* Calculate HP */

  /* For race */
  grade = raceGrades[raceIndex][hpIndex];
  
  raceHP =(int)(hpScale[grade][baseValueColumn] +
    hpScale[grade][scaleTo60Column]   * mainLevelUpTo60 +
    hpScale[grade][scaleOver30Column] * mainLevelOver30 +
    hpScale[grade][scaleOver60Column] * mainLevelOver60);

  /* For job */
  grade = jobGrades[mjob-1][hpIndex];
  
  jobHP = (int)(hpScale[grade][baseValueColumn] +
    hpScale[grade][scaleTo60Column]   * mainLevelUpTo60 +
    hpScale[grade][scaleOver30Column] * mainLevelOver30 +
    hpScale[grade][scaleOver60Column] * mainLevelOver60);

  /* Bonus increments */
  bonusHP = 2 * mainLevelOver10 +
            2 * mainLevelOver50andUnder60;


  /* For subjob */
  if (slvl > 0)
  {
    grade = jobGrades[sjob-1][hpIndex];
    
    sjobHP = (int)(hpScale[grade][baseValueColumn] +
      hpScale[grade][scaleTo60Column] * (slvl - 1) +
      subLevelOver10 + subLevelOver30);
      
    sjobHP = (sjobHP / 2);
    
    sjobHP = sjobHP + (int)(hpScale[grade][scaleOver30Column] * subLevelOver30);

  }
  else
  {
    sjobHP = 0;
  }

  return (raceHP + jobHP + sjobHP + bonusHP);

}
int CStats::calcMaxMP( int raceIndex, int mjob, int mlvl, int sjob, int slvl ) 
 {
  int baseValueColumn = 0;
  int scaleTo60Column = 1;
  int scaleOver60Column = 2;
  int mpIndex = 1;

  int raceMP;
  int jobMP;
  int sjobMP;
  int bonusMP = 0;
  
  int mainLevelOver60;
  int mainLevelTo60;


  int grade;
    mainLevelTo60 = mlvl - 1;
  if (mainLevelTo60 > 59)
    mainLevelTo60 = 59;

   mainLevelOver60 = mlvl - 60;
  if (mainLevelOver60 < 0)
    mainLevelOver60 = 0;

   if (jobGrades[mjob-1][mpIndex] == 0)
   {
    /* Ensure there's a subjob to check */
    if (sjob-1 >= 0)
    {
      if (jobGrades[sjob-1][mpIndex] == 0)
      {
        return 0;
      }
    }
    else
    {
      return 0;
    }
  }

  /* Calculate contributory portions for MP */

  bonusMP = 0;

  /* For race */
  grade = raceGrades[raceIndex][mpIndex];

  /* If main job does not have MP, calculate racial bonus based on subjob level (assuming subjob has MP)  */
  if (jobGrades[mjob-1][mpIndex] == 0)
  {
    /* Only calculate if subjob present */
    if (slvl > 0)
    {
      raceMP = (int)((mpScale[grade][baseValueColumn] +
        mpScale[grade][scaleTo60Column] * (slvl - 1)) / 2 );
    }
    else
    {
      raceMP = 0;
    }
  }
  else
  {
    /* Normal racial bonus */
    raceMP = (int)(
      mpScale[grade][baseValueColumn] +
      mpScale[grade][scaleTo60Column]   * mainLevelTo60 +
      mpScale[grade][scaleOver60Column] * mainLevelOver60);
  }

  /* For job */
  grade = jobGrades[mjob-1][mpIndex];

  /* Only calculate if job has an MP rating */
  if (grade > 0)
  {
    jobMP = (int)(
      mpScale[grade][baseValueColumn] +
      mpScale[grade][scaleTo60Column]   * mainLevelTo60 +
      mpScale[grade][scaleOver60Column] * mainLevelOver60);

  }
  else
  {
    jobMP = 0;
  }

  /* Subjob MP */
  if (slvl > 0)
  {
    grade = jobGrades[sjob-1][mpIndex];
    
    if (grade > 0)
    {
      sjobMP = (int)(
        (mpScale[grade][baseValueColumn] +
         mpScale[grade][scaleTo60Column] * (slvl - 1)
        ) / 2);
    }
    else
    {
      sjobMP = 0;
    }
  }
  else
  {
    sjobMP = 0;
  }
	
   return jobMP + sjobMP + raceMP + bonusMP;

}
int CStats::getStat(int statIndex, int raceIndex, int mjob, int mlvl, int sjob, int slvl ) 
{
  int baseValueColumn = 0;
  int scaleTo60Column = 1;
  int scaleOver60Column = 2;
  

  int raceStat;
  int jobStat;
  int sJobStat;

  int mlvlX = mlvl - 10;
  if(mlvlX < 0) {
	mlvlX = 0;
  }
  int mainLevelTo60;
  int mainLevelOver60;

  int grade;
    mainLevelTo60 = mlvl - 1;
  if (mainLevelTo60 > 59)
    mainLevelTo60 = 59;

   mainLevelOver60 = mlvl - 60;
  if (mainLevelOver60 < 0)
    mainLevelOver60 = 0;

  /* For race */
  grade = raceGrades[raceIndex][statIndex];
 // raceStat = (int)(statScale[grade][baseValueColumn] + statScale[grade][scaleTo60Column] * (mlvl - 1));
    raceStat = (int)
    floor(statScale[grade][baseValueColumn] +
    statScale[grade][scaleTo60Column] * mainLevelTo60);

  if (mlvl >= 75)
	  raceStat += (int)CUtil::round((statScale[grade][scaleOver60Column] * mainLevelOver60 - 0.01));
  else
	  raceStat += (int)floor((statScale[grade][scaleOver60Column] * mainLevelOver60));

  /*/ For job */
  grade = jobGrades[mjob-1][statIndex];
  jobStat = (int)
    floor(statScale[grade][baseValueColumn] +
    statScale[grade][scaleTo60Column] * mainLevelTo60);

  if (mlvl >= 75)
    jobStat += (int)CUtil::round((statScale[grade][scaleOver60Column] * mainLevelOver60 - 0.01));
  else
    jobStat += (int)floor((statScale[grade][scaleOver60Column] * mainLevelOver60));

  /* For subjob (subjob contributes half of its 'real' value) */
  if (slvl > 0)
  {
    grade = jobGrades[sjob-1][statIndex];
    sJobStat = (
      (int)(statScale[grade][baseValueColumn] +
       statScale[grade][scaleTo60Column] * (slvl - 1))
       / 2);
  }
  else
  {
    sJobStat = 0;
  }

  return raceStat + jobStat + sJobStat;
}

int CStats::calcStats(CBaseEntity * Cbe){
  int statIndex;
  int counter=0;
  short tempstat;
  unsigned char race = 0x00;

  if(Cbe->l.race == 1 || Cbe->l.race == 2)
	race = 0x00;
  if(Cbe->l.race == 3 || Cbe->l.race == 4)
	race = 0x01;
  if(Cbe->l.race == 5 || Cbe->l.race == 6)
	race = 0x02;
  if(Cbe->l.race == 7 )
	race = 0x03;
  if(Cbe->l.race == 8)
	race = 0x04;

 Cbe->m_maxHp = calcMaxHP(race, Cbe->m_jobMain, Cbe->m_lvlMain, Cbe->m_jobSub, Cbe->m_lvlSub ) ;
 Cbe->m_maxMp = calcMaxMP(race, Cbe->m_jobMain, Cbe->m_lvlMain, Cbe->m_jobSub, Cbe->m_lvlSub ) ;

 for (statIndex = 2; statIndex <= 8; statIndex++)
 {
	// Return the sum of the stat contributions 
	tempstat = getStat(statIndex, race, Cbe->m_jobMain, Cbe->m_lvlMain, Cbe->m_jobSub, Cbe->m_lvlSub ) ;
	memcpy(&(Cbe->stats.str)+counter, &tempstat, sizeof(short));
	counter ++;
 }

return 0;
}